//#include <core_cm3.h>
#include <stm32f10x.h>
#include <stm32f10x_spi.h>
#include <stm32f10x_gpio.h>
#include <stm32f10x_tim.h>
#include <stm32f10x_exti.h>
#include <stm32f10x_usart.h>
#include <misc.h>
#include <stm32f10x_rcc.h>
#include <Config.h>
#include <stdio.h>

#define Pin_ModeSel_A 		GPIO_Pin_4
#define Pin_ModeSel_B 		GPIO_Pin_5
#define GPIO_ModeSel  		GPIOC
#define RCC_ModeSel_ENABLE 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE)

unsigned long delaycount = 0;

void delayms(unsigned long dvalue);
void timer2_config(TIM_SET set);

/*
 *
 */
void SetSysClk(void) {
	ErrorStatus HSEStartUpStatus;
	RCC_DeInit();
	/* Enable HSE */
	RCC_HSEConfig(RCC_HSE_ON);
	/* Wait till HSE is ready */
	HSEStartUpStatus = RCC_WaitForHSEStartUp();
	if (HSEStartUpStatus == SUCCESS) {
		/* Flash 0 wait state */
		//		FLASH_SetLatency(FLASH_Latency_0);
		/* HCLK = SYSCLK */
		RCC_HCLKConfig(RCC_SYSCLK_Div1);
		/* PCLK2 = HCLK */
		RCC_PCLK2Config(RCC_HCLK_Div1);
		/* PCLK1 = HCLK */
		RCC_PCLK1Config(RCC_HCLK_Div1);
		/* PLLCLK = (8MHz) * 9 = 72 MHz */
		RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
		/* Enable PLL */
		RCC_PLLCmd(ENABLE);
		/* Wait till PLL is ready */
		while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {
		}
		/* Select PLL as system clock source */
		RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
		/* Wait till PLL is used as system clock source */
		while (RCC_GetSYSCLKSource() != 0x08) {
		}
	} else {
		/* If HSE fails to start-up, the application will have wrong clock configuration.
		 User can add here some code to deal with this error */

		/* Go to infinite loop */
		while (1) {
		}
	}
}

/*
 *
 */
void General_Config(void) {
	GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, DISABLE);
}
/*
 * ****************************************
 * provide function delay dvalue(s)
 * ****************************************
 */
void delays(unsigned long dvalue) {
	if (dvalue != 0) {
		timer2_config(Sec);
		delaycount = 0;
		SwitchTIM2IRQ(ENABLE);
		while (delaycount <= (dvalue))
			;
		SwitchTIM2IRQ(DISABLE);
	}
}

/*
 * ****************************************
 * provide function delay dvalue(ms)
 * ****************************************
 */
void delayms(unsigned long dvalue) {
	if (dvalue != 0) {
		timer2_config(mSec);
		delaycount = 0;
		SwitchTIM2IRQ(ENABLE);
		while (delaycount <= (dvalue))
			;
		SwitchTIM2IRQ(DISABLE);
	}
}

/*
 * ****************************************
 * provide function delay dvalue(us)
 * ****************************************
 */
void delayus(unsigned long dvalue) {
	if (dvalue != 0) {
		timer2_config(uSec);
		delaycount = 0;
		SwitchTIM2IRQ(ENABLE);
		while (delaycount <= dvalue)
			;
		SwitchTIM2IRQ(DISABLE);
	}
}

/*
 *
 */
void ModeSel_Configuration(void) {
	RCC_ModeSel_ENABLE;
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = Pin_ModeSel_A | Pin_ModeSel_B;
	//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_Init(GPIO_ModeSel, &GPIO_InitStructure);
	GPIO_ResetBits(GPIO_ModeSel, Pin_ModeSel_A);
	GPIO_ResetBits(GPIO_ModeSel, Pin_ModeSel_B);
}

/*
 *
 */
MODESEL ModeSel(void) {
	unsigned int Mode = 0;
	OUTPUT_USARTTerm;
	if (GPIO_ReadInputDataBit(GPIO_ModeSel, Pin_ModeSel_A) == Bit_SET) {
		Mode = Mode | 1;
	}
	if (GPIO_ReadInputDataBit(GPIO_ModeSel, Pin_ModeSel_B) == Bit_SET) {
		Mode = Mode | 1 << 1;
	}
	return Mode;
}

/************************************************************************
 * enable USART1 in vector table
 *
 ************************************************************************/
void SwitchUSART1IRQ(FunctionalState state) {
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelCmd = state;
	NVIC_Init(&NVIC_InitStructure);
}

/************************************************************************
 * enable TIM2 in vector table
 *
 ************************************************************************/
void SwitchTIM2IRQ(FunctionalState state) {
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = state;
	NVIC_Init(&NVIC_InitStructure);
}

/************************************************************************
 * enable TIM2 in vector table
 *
 ************************************************************************/
void SwitchTIM3IRQ(FunctionalState state) {
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = state;
	NVIC_Init(&NVIC_InitStructure);
}

/************************************************************************
 * enable TIM3 in vector table
 *
 ************************************************************************/
void SwitchTIM4IRQ(FunctionalState state) {
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = state;
	NVIC_Init(&NVIC_InitStructure);
}

/************************************************************************
 * enable TIM5 in vector table
 *
 ************************************************************************/
void SwitchTIM5IRQ(FunctionalState state) {
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = state;
	NVIC_Init(&NVIC_InitStructure);
}

/************************************************************************
 * enable TIM6 in vector table
 *
 ************************************************************************/
void SwitchTIM6IRQ(FunctionalState state) {
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = state;
	NVIC_Init(&NVIC_InitStructure);
}

/************************************************************************
 * enable TIM7 in vector table
 *
 ************************************************************************/
void SwitchTIM7IRQ(FunctionalState state) {
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = state;
	NVIC_Init(&NVIC_InitStructure);
}

/*
 *
 */
void SwitchSPI2IRQ(FunctionalState state) {
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = SPI2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = state;
	NVIC_Init(&NVIC_InitStructure);
}

void SwitchEXTI2IRQ(FunctionalState state) {
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = state;
	NVIC_Init(&NVIC_InitStructure);
}

/*
 * *****************************************************************
 * contain configuration of all vector interrupt used in program
 * *****************************************************************
 */
void SwitchAllIRQ(FunctionalState state) {
	/* Enable the TIM2 global Interrupt */
	SwitchTIM2IRQ(state);
	/*Enable USART1 interrupt vector*/
	SwitchUSART1IRQ(state);
	/**/
	SwitchTIM4IRQ(state);
	/**/
	SwitchSPI2IRQ(state);
	SwitchEXTI2IRQ(state);
}

/*
 * *************************************************************
 * config timer2,
 * use for delay purpose only
 * *************************************************************
 */
void timer2_config(TIM_SET set) {
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
	// Time base conf
	if (set == uSec) {
		TIM_TimeBaseStructure.TIM_Period = 2 - 1;
		TIM_TimeBaseStructure.TIM_Prescaler = 36;
	} else if (set == mSec) {
		TIM_TimeBaseStructure.TIM_Period = 1000 - 1;
		TIM_TimeBaseStructure.TIM_Prescaler = 72;
	} else if (set == Sec) {
		TIM_TimeBaseStructure.TIM_Period = 2000 - 1;
		TIM_TimeBaseStructure.TIM_Prescaler = 36000;
	}
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
	TIM_Cmd(TIM2, ENABLE);
}

/*****************************************************************
 * config timer3,
 *
 **************************************************************/
void timer3_config(void) {
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
	// Time base conf, tick every 1ms
	TIM_TimeBaseStructure.TIM_Period = 1000 - 1;
	TIM_TimeBaseStructure.TIM_Prescaler = 72;
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	TIM_Cmd(TIM3, ENABLE);
}

/*
 * *************************************************************
 * config timer4,
 * use for generate DAC
 * *************************************************************
 */
void timer4_config(unsigned int microsec) {
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
	// Time base conf, tick every (n)us
	TIM_TimeBaseStructure.TIM_Period = (2 - 1);
	TIM_TimeBaseStructure.TIM_Prescaler = 36 * microsec;
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	//TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
	TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
	TIM_Cmd(TIM4, ENABLE);
}

/*****************************************************************
 * config timer5,
 *
 **************************************************************/
void timer5_config(void) {
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
	// Time base conf, tick every 100ms
	TIM_TimeBaseStructure.TIM_Period = 1000 - 1;
	TIM_TimeBaseStructure.TIM_Prescaler = 72 * 100;
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE);
	TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
	TIM_Cmd(TIM5, ENABLE);
}

/*****************************************************************
 * config timer6,
 *
 **************************************************************/
void timer6_config(void) {
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE);
	// Time base conf, tick every 30ms
	TIM_TimeBaseStructure.TIM_Period = 1000 - 1;
	TIM_TimeBaseStructure.TIM_Prescaler = 72 * 30;
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
	TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
	TIM_Cmd(TIM6, ENABLE);
}

/*****************************************************************
 * config timer7,
 * feed buffer WAV
 **************************************************************/
void timer7_config(unsigned int microsec) {
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7, ENABLE);
	// Time base conf, tick every (n)us
	TIM_TimeBaseStructure.TIM_Period = (2 - 1);
	TIM_TimeBaseStructure.TIM_Prescaler = 36 * microsec;
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE);
	TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);
	TIM_Cmd(TIM7, ENABLE);
}

/*
 * ************************************************************
 * below is IRQhandler functions
 * ************************************************************
 */
void TIM2_IRQHandler(void) {
	if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) {
		delaycount++;
		TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	}
}

